﻿// ===============================================================================
// XCI.NET 西安交通信息WinForm开发框架 2018 版权所有
// ===============================================================================
using System;
using System.Data;
using System.Data.Common;
using System.Reflection;
using XCI.Core;
using XCI.Data.Entity;
using XCI.Helper;

namespace XCI.Data.Provider
{
    /// <summary>
    /// Oracle数据库实现
    /// </summary>
    public class OracleProvider : BaseProvider
    {
        private static DbProviderFactory factory;
        private static readonly object CursorValue = EnumHelper.ToEnum("Oracle.ManagedDataAccess.Client.OracleDbType,Oracle.ManagedDataAccess", "RefCursor");
        private static FastInvokeHandler _bindInvoke;
        private static FastInvokeHandler _paramInvoke;

        /// <summary>
        /// 获取数据对象创建工厂
        /// </summary>
        /// <returns></returns>
        public override DbProviderFactory GetDbProviderFactory()
        {
            return factory ?? (factory = GetFactory("Oracle.ManagedDataAccess.Client.OracleClientFactory,Oracle.ManagedDataAccess"));
        }

        /// <summary>
        /// 获取参数前缀
        /// </summary>
        public override string GetParamPrefix()
        {
            return ":";
        }

        /// <summary>
        /// 执行命令之前调用,可以修改DbCommand对象
        /// </summary>
        /// <param name="cmd">命令对象</param>
        public override void BeforeExecute(IDbCommand cmd)
        {
            if (_bindInvoke == null)
            {
                var property = cmd.GetType().GetProperty("BindByName");
                if (property != null)
                {
                    _bindInvoke = ObjectHelper.GetFastInvoker(property.GetSetMethod());
                }
            }

            _bindInvoke?.Invoke(cmd, true);
        }

        /// <summary>
        /// 添加游标参数（针对Oracle数据库）
        /// </summary>
        /// <param name="param">参数对象</param>
        public override void SetCursorParam(IDbDataParameter param)
        {
            param.Direction = System.Data.ParameterDirection.Output;

            if (_paramInvoke == null)
            {
                var property = param.GetType().GetProperty("OracleDbType");
                if (property != null)
                {
                    _paramInvoke = ObjectHelper.GetFastInvoker(property.GetSetMethod());
                }
            }
            _paramInvoke?.Invoke(param, CursorValue);
        }

        /// <summary>
        /// 获取Insert语句模板
        /// </summary>
        /// <param name="entityData">实体信息</param>
        /// <param name="cmd">Insert命令对象</param>
        public override void PrepInsert(EntityData entityData, DbCommand cmd)
        {
            if (entityData.PrimaryAttr == null || !entityData.PrimaryAttr.Auto) return;

            cmd.CommandText += $" returning {entityData.PrimaryProperty.DbName} into :newid";
            var param = cmd.CreateParameter();
            param.ParameterName = ":newid";
            param.Value = DBNull.Value;
            param.Direction = ParameterDirection.ReturnValue;
            param.DbType = DbType.Int64;
            cmd.Parameters.Add(param);
        }

        /// <summary>
        /// 获取分页语句模板
        /// </summary>
        /// <param name="sql">查询语句</param>
        /// <param name="orderBy"></param>
        /// <param name="startIndex"></param>
        /// <param name="endIndex"></param>
        /// <returns>获取分页语句模板</returns>
        public override string GetPageStatement(string sql, string orderBy, int startIndex, int endIndex)
        {
            string result = @"SELECT * FROM(SELECT grid.*, rownum FROM ({0} {1}) grid WHERE ROWNUM <= {2}) WHERE rownum >= {3}";
            return string.Format(result, sql, orderBy, endIndex, startIndex);
        }
    }
}